import { degrees, PDFDocument, rgb, StandardFonts } from 'pdf-lib';

/**
 * 浏览器打开新页签预览pdf
 * blob（必选）: pdf文件信息（Blob对象）【Blob】
 * docTitle（可选）: 浏览器打开新页签的title  【String】
 * isAddWatermark（可选，默认为false）: 是否需要添加水印 【Boolean】
 * watermark（必选）：水印信息 【Object: { type: string, text: string, image:{ bytes: ArrayBuffer, imageType: string } }】
 * watermark.type（可选）：类型 可选值：text、image、canvas
 * watermark.text（watermark.type为image时不填，否则必填）：水印文本。注意：如果watermark.type值为text，text取值仅支持拉丁字母中的218个字符。详见：https://www.npmjs.com/package/pdf-lib
 * watermark.image（watermark.type为image时必填，否则不填）：水印图片
 * watermark.image.bytes：图片ArrayBuffer
 * watermark.image.imageType：图片类型。可选值：png、jpg
 * Edit By WFT
 */
export default class PreviewPdf {
    // @ts-ignore
    constructor({ blob, docTitle, isAddWatermark = false, watermark: { type = 'text', text = 'WFT', image } }) {
        const _self = this
        if(!blob) {
            console.error('[PDF Blob Is a required parameter]')
            return;
        }
        if(!isAddWatermark) { // 不添加水印
            _self.preView(blob, docTitle)
        } else {
            let bytes: any,imageType: any;
            if(type == 'image') {
                if(!image) {
                    console.error('["image" Is a required parameter]')
                    return;
                }
                bytes = image.bytes
                imageType = image.imageType
            }
            const map = {
                'text': _self.addTextWatermark.bind(_self),
                'image': _self.addImageWatermark.bind(_self),
                'canvas': _self.addCanvasWatermark.bind(_self)
            }
            blob.arrayBuffer().then(async (buffer: any) => {
                const existingPdfBytes = buffer
                const pdfDoc = await PDFDocument.load(existingPdfBytes)
                let params
                if(type == 'text') params = { pdfDoc, text, docTitle }
                if(type == 'image') params = { pdfDoc, bytes, imageType, docTitle }
                if(type == 'canvas') params = { pdfDoc, text, docTitle }
                // @ts-ignore
                map[type](params)
            }).catch((e: any) => console.error('[Preview Pdf Error]:', e))
        }
    }

    // 添加 Text 水印
    // @ts-ignore
    async addTextWatermark({ pdfDoc, text, docTitle }) {
        // console.log(StandardFonts, 'StandardFonts-->>') // 字体
        const helveticaFont = await pdfDoc.embedFont(StandardFonts.Helvetica)
        const pages = pdfDoc.getPages()
        for(let i = 0; i < pages.length; i++) {
            let page = pages[i]
            let { width, height } = page.getSize()
            for(let i = 0; i < 6; i++) {
                for(let j = 0; j < 6; j++) {
                    page.drawText(text, {
                        x: j * 100,
                        y: height / 5 + i * 100,
                        size: 30,
                        font: helveticaFont,
                        color: rgb(0.95, 0.1, 0.1),
                        opacity: 0.2,
                        rotate: degrees(-35),
                    })
                }
            }
        }
        // 序列化为字节
        const pdfBytes = await pdfDoc.save()
        this.preView(pdfBytes, docTitle)
    }

    // 添加 image 水印
    // @ts-ignore
    async addImageWatermark({ pdfDoc, bytes, imageType, docTitle }) {
        // 嵌入JPG图像字节和PNG图像字节
        let image
        const maps = {
            'jpg': pdfDoc.embedJpg.bind(pdfDoc),
            'png': pdfDoc.embedPng.bind(pdfDoc)
        }
        // @ts-ignore
        image = await maps[imageType](bytes)
        // 将JPG图像的宽度/高度缩小到原始大小的50%
        const dims = image.scale(0.5)
        const pages = pdfDoc.getPages()
        for(let i = 0; i < pages.length; i++) {
            let page = pages[i]
            let { width, height } = page.getSize()
            for(let i = 0; i < 6; i++) {
                for(let j = 0; j < 6; j++) {
                    page.drawImage(image, {
                        x: width / 5 - dims.width / 2 + j * 100,
                        y: height / 5 - dims.height / 2 + i * 100,
                        width: dims.width,
                        height: dims.height,
                        rotate: degrees(-35)
                    })
                }
            }
        }
        // 序列化为字节
        const pdfBytes = await pdfDoc.save()
        this.preView(pdfBytes, docTitle)
    }

    // 添加 canvas 水印
    // @ts-ignore
    addCanvasWatermark({ pdfDoc, text, docTitle }) {
        // 旋转角度大小
        const rotateAngle = Math.PI / 6;

        // labels是要显示的水印文字，垂直排列
        let labels = new Array();
        labels.push(text);

        const pages = pdfDoc.getPages()

        const size = pages[0].getSize()

        let pageWidth = size.width
        let pageHeight = size.height

        let canvas = document.createElement('canvas');
        let canvasWidth = canvas.width = pageWidth;
        let canvasHeight = canvas.height = pageHeight;

        const context: any = canvas.getContext('2d');
        context.font = "15px Arial";

        // 先平移到画布中心
        context.translate(pageWidth / 2, pageHeight / 2 - 250);
        // 在绕画布逆方向旋转30度
        context.rotate(-rotateAngle);
        // 在还原画布的坐标中心
        context.translate(-pageWidth / 2, -pageHeight / 2);

        // 获取文本的最大长度
        let textWidth = Math.max(...labels.map(item => context.measureText(item).width));

        let lineHeight = 15, fontHeight = 12, positionY: number, i
        i = 0, positionY = 0
        while (positionY <= pageHeight) {
            positionY = positionY + lineHeight * 5
            i++
        }
        canvasWidth += Math.sin(rotateAngle) * (positionY + i * fontHeight) // 给canvas加上画布向左偏移的最大距离
        canvasHeight = 2 * canvasHeight
        for (positionY = 0, i = 0; positionY <= canvasHeight; positionY = positionY + lineHeight * 5) {
            // 进行画布偏移是为了让画布旋转之后水印能够左对齐;
            context.translate(-(Math.sin(rotateAngle) * (positionY + i * fontHeight)), 0);
            for (let positionX = 0; positionX < canvasWidth; positionX += 2 * textWidth) {
                let spacing = 0;
                labels.forEach(item => {
                    context.fillText(item, positionX, positionY + spacing);
                    context.fillStyle = 'rgba(187, 187, 187, .8)'; // 字体颜色
                    spacing = spacing + lineHeight;
                })
            }
            context.translate(Math.sin(rotateAngle) * (positionY + i * fontHeight), 0);
            context.restore();
            i++
        }
        // 图片的base64编码路径
        let dataUrl = canvas.toDataURL('image/png');
        // 使用Xhr请求获取图片Blob
        let xhr = new XMLHttpRequest();
        xhr.open("get", dataUrl, true);
        xhr.responseType = "blob";
        xhr.onload = (res: any) => {
            const imgBlob = res.target.response
            // 获取Blob图片Buffer
            imgBlob.arrayBuffer().then(async (buffer: any) => {
                const pngImage = await pdfDoc.embedPng(buffer)
                for(let i = 0; i < pages.length; i++) {
                    pages[i].drawImage(pngImage)
                }
                // 序列化为字节
                const pdfBytes = await pdfDoc.save()
                this.preView(pdfBytes, docTitle)
            })
        }
        xhr.send();
    }

    // 预览
    preView(stream: any, docTitle: any) {
        const URL = window.URL || window.webkitURL;
        const href = URL.createObjectURL(new Blob([stream], { type: 'application/pdf;charset=utf-8' }))
        const wo: any = window.open(href)
        // 设置新打开的页签 document title
        let timer = setInterval(() => {
            if(wo.closed) {
                clearInterval(timer)
            } else {
                wo.document.title = docTitle
            }
        }, 500)
    }
}